[Xamarin.Mac] フォルダ内の画像を一覧表示してみました
1 はじめに
CX事業本部の平内(SIN)です。
Xamarin.Macを使用すると、C#でネイティブなMacのアプリが作成可能です。 ここでは、私自身がXamarin.Macに入門して学習した事項を覚書として書かせて頂いています。
今回は、フォルダを指定して、その中にある画像ファイルを一覧表示してみました。
2 画面構成
Interface Builderでの画面設計です。
最初に、ウインドウいっぱいに上下分割のSplit Viewを置きました。そして、上側のビューの高さを固定し、ImageButtonを配置しました。
Outletは、ImageButton(NSButton)とCollectionView(NSCollectionView)という名前で作成しています。
3 NSCollectionViewItem
ファイル > 新しいファイル > Mac > View Controllerと辿り、新規にビューを作成します。(ここでは、名前をPictureViewとしました)
この時、以下の3つのファイルが生成されますが、PictureView.xibは、PictureViewController.xibにRenameしています。
- PictureView.cs
- PictureView.xib
- PictureViewController.cs
Interface Builderで、LabelとImageViewを配置しました。
Image Viewは、Owner(PictureViewController.cs)のImageプロパティにバインディングしています。
Labelは、OwnerのNameプロパティにバインディングしています。
PictureViewController.csは、継承元をNSCollectionViewItemに変更し、バインディング用に2つのプロパティを公開しています。
PictureViewController.cs
public partial class PictureViewController : NSCollectionViewItem { NSImage _image; string _name; [Export("Image")] public NSImage Image { get { return _image; } set { WillChangeValue("Image"); _image = value; DidChangeValue("Image"); } } [Export("Name")] public string Name { get { return _name; } set { WillChangeValue("Name"); _name = value; DidChangeValue("Name"); } } // ・・・略・・・ }
4 Delegate/DataSource
デリゲートは、NSCollectionViewDelegateFlowLayoutを継承して作成しています。
public class CollectionViewDelegate: NSCollectionViewDelegateFlowLayout { public CollectionViewDelegate() { } } }
データソースは、NSCollectionViewDataSourceを継承して作成し、データとして、ファイルパスの一覧を保持させます。
データには、画像ファイルのパスが入っているので、GetItem()の段階で、NSImageを生成して、PictureViewControllerのプロパティを更新しています。
public class CollectionViewDataSource : NSCollectionViewDataSource { // ファイル(パス)の一覧 public List<string> Files = new List<String>(); public CollectionViewDataSource() {} public override NSCollectionViewItem GetItem(NSCollectionView collectionView, NSIndexPath indexPath) { var item = collectionView.MakeItem("cell", indexPath) as PictureViewController; var file = Files[(int)indexPath.Item]; // ファイル名 item.Name = Path.GetFileName(file); // 画像 item.Image = new NSImage(file); return item; } public override nint GetNumberofItems(NSCollectionView collectionView, nint section) { return Files.Count; } }
5 ViewController
ViewController の ViewDidLoad() で、作成したデータソースとデリゲートをCollection Viewにセットしています。
また、ボタンをクリックされた際には、ディレクトリ選択のダイアログを表示し、選択された場合は、その中のファイル(jpg)一覧で、データソースを初期化します。
ViewController.cs
public partial class ViewController : NSViewController { public ViewController(IntPtr handle) : base(handle) { } public override void ViewDidLoad() { base.ViewDidLoad(); // Openボタンがクリックれた時のイベントを定義 ImageButton.Activated += ImageButton_Activated; // PictureViewControllerの登録 CollectionView.RegisterClassForItem(typeof(PictureViewController), "cell"); // DataSource CollectionView.DataSource = new CollectionViewDataSource(); // Flow layout var flowLayout = new NSCollectionViewFlowLayout() { ItemSize = new CGSize(150, 150), SectionInset = new NSEdgeInsets(10, 10, 10, 20), MinimumInteritemSpacing = 10, MinimumLineSpacing = 10 }; CollectionView.WantsLayer = true; CollectionView.CollectionViewLayout = flowLayout; // Delegate CollectionView.Delegate = new CollectionViewDelegate(); } // Openクリック時の処理 private void ImageButton_Activated(object sender, EventArgs e) { // ディレクトリ選択 var dlg = NSOpenPanel.OpenPanel; dlg.CanChooseDirectories = true; if(dlg.RunModal() == 1) { var url = dlg.Urls[0]; if(url != null) { // 選択されたディレクトリ内のjpgの一覧を取得 string[] files = Directory.GetFiles(url.Path, "*.jpg"); // Collection Viewのデータソースを更新する ((CollectionViewDataSource)CollectionView.DataSource).Files = files.ToList(); } } CollectionView.ReloadData(); } // ・・・略・・・ }
6 最後に
今回は、フォルダを指定して画像ファイルを一覧してみました。データバインディングのコツが掴めれば、比較的にスムーズに実装が進みそうな気がしてます。
個人的には、ImageViewのバインディングタブでは、Dataが一番上になっているので、間違ってこちらでBind toしないように注意が必要かなと思いました。